﻿using System;
using System.Collections;
using DataFiller.DataStorage.Extension.Excel.Holders;
using DataFiller.DataStorage.Extension.Excel.Locaters;
using DataFiller.DataStorage.Extension.Interpreters;
using DataFiller.DataStorage.Extension.Regions;
using DataFiller.DataStorage.Holders;
using DataFiller.DataStorage.Regions;
using DataFiller.DataStorage.Store;

namespace DataFiller.DataStorage.Extension
{
    public class ExcelDataMap<T> : DataMap<T>
    {
        /// <summary>
        /// fix the row number to fit the book that had been filled
        /// </summary>
        public override void AddRegion(T key, IDataRegion<T> region)
        {
            ExcelRowRegion<T> excelRegion = region as ExcelRowRegion<T>;
            if (excelRegion == null)
                throw new ArgumentException("given region is not a excel region");

            //each region represents at least one row, 
            //that  begin with the row number which is the sum of all the prior region's row count
            excelRegion.StartRowNumber = 0;
            foreach (ExcelRowRegion<T> addedRegion in base._Resgions.Values)
                excelRegion.StartRowNumber += addedRegion.RowCount;

            base.AddRegion(key, excelRegion);
        }

        protected override void AddInterpretedData(IDataHolder holder, object value, IDataRegion<T> region)
        {
            DataEncapsulater tempValue = value as DataEncapsulater;
            //null represents that the string is not a placehoder or we can't get the corresponding data
            if (value == null || tempValue == null)
            {
                // we use the original data that passed in, without any change
                region.AddHolder(holder);
            }
            else if (IsIEnumerable(tempValue.Data))
            {
                //the place holder represents a collection
                ProcessCollectionData(holder, tempValue, region);
            }
            else
            {
                //the place holder represents a single value
                holder.Data = tempValue.Data;
                region.AddHolder(holder);
            }
        }

        private static void ProcessCollectionData(IDataHolder holder, DataEncapsulater value, IDataRegion<T> region)
        {
            ExcelHolder eh = (ExcelHolder)holder;
            ExcelLocater el = (ExcelLocater)eh.Locater;
            int colNumber = el.ColNumber;
            int rowNumber = el.RowNumber;

            var tempValue = value.Data as IEnumerable;
            foreach (var item in tempValue)
            {
                var tempLocater = new ExcelLocater(rowNumber, colNumber);
                ExcelHolder newEh = new ExcelHolder(tempLocater) 
                {
                    Data = item,
                    Style = eh.Style,
                    Type = eh.Type
                };

                if (value.Orientation == ExtensionDirection.Horizontal)
                    colNumber++;
                else if (value.Orientation == ExtensionDirection.Vertical)
                    rowNumber++;
                else
                    throw new Exception(string.Format("invalid orientation {0}", value.Orientation));

                region.AddHolder(newEh);
            }
        }

        private static bool IsIEnumerable(object value)
        {
            //string is also implemented IEnumerable
            return !(value is string) && value is IEnumerable;
        }
    }
}
